package projects.coloring.nodes.nodeImplementations;

import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;

import org.omg.CORBA.PUBLIC_MEMBER;

import com.sun.org.apache.xml.internal.resolver.helpers.PublicId;

import projects.coloring.nodes.messages.CMessage;
import projects.coloring.nodes.timers.CTimer;
import sinalgo.configuration.WrongConfigurationException;
import sinalgo.gui.transformation.PositionTransformation;
import sinalgo.nodes.Node;
import sinalgo.nodes.Position;
import sinalgo.nodes.edges.Edge;
import sinalgo.nodes.messages.Inbox;
import sinalgo.nodes.messages.Message;

class ssdata {
	int id;
	int sscolor;
	float ssdensity;
	ssdata (int id,int sscolor,float ssdensity)
	{
		this.id= id ;
		this.sscolor=sscolor;
		this.ssdensity = ssdensity;
	}
}
public class CNode extends Node{
	private int sscolor; 
	private final int nb = 10; 
	private int count =0;
	private final Color tab[]= {Color.BLUE,Color.CYAN,Color.GREEN,Color.LIGHT_GRAY,Color.MAGENTA,Color.ORANGE,Color.PINK,Color.RED,Color.YELLOW,Color.WHITE};
	private Hashtable<Integer,ssdata> neighstate;
	
	//private Hashtable<Integer, Node> neighNode;--------------------
	private ArrayList<Node> neighNode = new ArrayList<>();
	private int numberofNeighbor=0;
	private int nEdgeneighbor=0;
	private float cluterHead=0;
	private float myDensity=0;
	private ssdata clusterNode;
	private String str;
	
	//---------------------------
	public int getSSColor(){
		return sscolor ;
	}
	public float getSSdensity()
	{
		return myDensity ;
		
	}
	public Color RGBColor(){
		return tab [getSSColor()];
	}
	public void setSSColor (int c)
	{
		this.sscolor=c ;
	}
	public void setSSdensity(float density){
		this.myDensity=density;
	}
	public void initSSColor (int range ){
		setSSColor((int)(Math.random()* range) % range);
	}
	public void compute ()
	{

		Boolean same =false;		
		Iterator<Edge> it = this.outgoingConnections.iterator();
		boolean SC[] = new boolean[nb];
		for (int i=0 ;i<SC.length;i++)
		{
			SC[i]=false;
			
		}
		//check the status of neighbor node 
		while(it.hasNext()){
			Edge e =it.next();
			
			//add neighNode to caculate the density
			System.out.println("node oppsitor"+e.endNode.toString());
			neighNode.add(e.endNode);	
			ssdata tmp = neighstate.get(new Integer(e.endNode.ID));
			//System.out.println("size of neighbor"+neighstate.size());
			//System.out.println("endnode"+e.endNode.ID);
			numberofNeighbor++;
			if (tmp!= null){
				if(tmp.sscolor==this.getSSColor()){
					same= true;
					
				}
				SC[tmp.sscolor]=true;
				
				System.out.println("neighbor_sensity "+e.endNode.ID+"/"+tmp.ssdensity);
				if(cluterHead<tmp.ssdensity)
				{
					clusterNode=tmp;
					cluterHead=tmp.ssdensity;
				}
				if(cluterHead==tmp.ssdensity)
				{
					if ( (clusterNode!= null) && (clusterNode.sscolor>tmp.sscolor)) {
						clusterNode=tmp;
						
					}
				}
				if((clusterNode!= null)&&(cluterHead<this.myDensity))
				{
					clusterNode.id=this.ID;
					clusterNode.sscolor=this.sscolor;
					clusterNode.ssdensity=this.myDensity;
				}
			}
			
		}
	// caculate the density of node 
		System.out.println("neighbor node "+neighNode.size());
		for(int i =0 ; i<neighNode.size()-1;i++)
		{
			
			Node e1 = neighNode.get(i);
			//System.out.println("i="+i +"e1="+e1.ID);
			for(int j=i+1;j<numberofNeighbor;j++)
			{
				
				Node e2 =neighNode.get(j);
				//System.out.println("j="+j+"e2= " +e2.ID);
				//System.out.println(e1.ID+ e2.ID);
				if(checkEdge(e1, e2)==true)
				{		
					nEdgeneighbor ++;
				}
			}
			
		}

		System.out.println("neighbor node "+neighNode.size());
		myDensity=(float)(numberofNeighbor+nEdgeneighbor)/numberofNeighbor;
		System.out.println(nEdgeneighbor);
		System.out.println("mydensity"+myDensity);
		System.out.println("Cluster head"+this.cluterHead);
		
		if(clusterNode!=null)
		{
			str=String.valueOf(clusterNode.id);
			System.out.println("cluster node"+ clusterNode.ssdensity +"ID"+clusterNode.id);
		}
		numberofNeighbor=0;
		nEdgeneighbor=0;
		//---------------------------------------
		//check the same color
		if (same){
			int available =0;
			for (int i =0;i<SC.length;i++)
			{
				if(SC[i]==false)
					available++;
				
			}
			if(available==0)
			{
				return;
			}
			int choice = ((int)(Math.random() * 10000)) % available +1;
			int i=0;
			while (choice >0){
				if(SC[i]==false)
					 choice --;
				if (choice >0) i++;
			}
			this.setSSColor(i);
		}
		neighNode.clear();
		
	}
	
//function check the same edge between 2 node
	public boolean checkEdge(Node e1, Node e2)
	{
		Iterator<Edge> eIter = e1.outgoingConnections.iterator();
		
		while(eIter.hasNext()){
			Edge e = eIter.next();
			Node n1 = e.endNode;
			if(n1.ID==e2.ID)
			{
			//	System.out.println("edge"+e1.ID+"E" +e2.ID +"true");
				return true;
			}
		}
		return false ;
	}
	
	public void init()
		{
			initSSColor(nb);
			(new CTimer(this,50)).startRelative(50,this);
			this.neighstate= new Hashtable<Integer,ssdata>(this.outgoingConnections.size());
			System.out.println("size of outgoing connection"+this.outgoingConnections.size());
			
			
		}
	public void neighborhoodChange(){}
	public void postStep(){}
	public String toString(){
		//String s = "Node("+ this.ID + ") [";
		String s = "Neighbors [";
		Iterator<Edge> edgeIter = this.outgoingConnections.iterator();
		while(edgeIter.hasNext()){
			Edge e = edgeIter.next();
			Node n = e.endNode;
			s+=n.ID+" ";
		}
		
		return s + "]"+" ClusterHead"+String.format("%.2f",this.cluterHead)+" "+"Node"+str;
	
	}
	public void checkRequirements() throws WrongConfigurationException{}
	public void draw (Graphics g, PositionTransformation pt , boolean highlight)
	{
		Color c; 
		this.setColor(this.RGBColor());
		String text =this.ID+"/"+String.format("%.2f", myDensity);
		c=Color.BLACK;
		super.drawNodeAsDiskWithText(g, pt, highlight, text, 20, c);
	}
	@Override
	public void handleMessages(Inbox inbox) {
		// TODO Auto-generated method stub
		if(inbox.hasNext()==false )
		{
			return;
		}
		while(inbox.hasNext())
		{
			
			Message msg=inbox.next();
			if(msg instanceof CMessage){
				ssdata tmp =new ssdata (((CMessage) msg).id,((CMessage) msg).sscolor,((CMessage)msg).ssdensity);
				neighstate.put(new Integer(((CMessage) msg).id), tmp);
				count++;
				System.out.println("receive information from neighbor"+count);
				compute();
			}
		}
	}
	@Override
	public void preStep() {
		// TODO Auto-generated method stub
		
	}
	

}
